﻿namespace NTLib.Pipe.Containers
{
    using NTLib.Core.Pool;
    using NTLib.Pipe.Exceptions;
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using NTLib.Core.Args;


    /// <summary>
    ///  Class used to give only access to the pipe in push and send
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class BasePipeRelay<T> : BasePipePoolItem, IPipeManipulator<T>
    {
        #region Fields

        private IPipe<T> _pipe;
        private PipeStatus _status;

        #endregion

        #region Properties

        /// <summary>
        /// Gets the unique ID.
        /// </summary>
        public override Guid Id
        {
            get
            {
                CheckInitialized();
                return this._pipe.Id;
            }
        }

        /// <summary>
        /// Gets or sets the source.
        /// </summary>
        protected IPipe<T> Source
        {
            get { return this._pipe; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Pop an item from the item's queue if the pipe permits it.
        /// </summary>
        /// <param name="token">Token used to cancel the task of waiting item.</param>
        /// <returns>
        /// Asynchronious task that wait there is an item in the pipe.
        /// </returns>
        /// <exception cref="PipeActionNotPermitsException">PopAsync</exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual Task<T> PopAsync(CancellationToken token = default(CancellationToken))
        {
            CheckInitialized();
            return this._pipe.PopAsync(token);
        }

        ///// <summary>
        ///// Push an item to the item's queue if the pipe permits it and wait that the item is process by the other side.
        ///// </summary>
        ///// <typeparam name="U">Type of the response you are waiting by this specific push.</typeparam>
        ///// <param name="item">The item.</param>
        ///// <param name="token">Tpken used to cancel the task that wait to items arrived on the other side.</param>
        ///// <returns>
        ///// Asynchronious task that permit to wait that the item have been pop by the other side.
        ///// </returns>
        //[MethodImpl(MethodImplOptions.AggressiveInlining)]
        //public virtual Task<U> PushAsync<U>(T item, CancellationToken token = default(CancellationToken))
        //{
        //    CheckInitialized();
        //    return this._pipe.PushAsync<U>(item, token);
        //}

        /// <summary>
        /// Send an item to the item's queue if the pipe permits it.
        /// Attention this method doesn't wait that the item achieved the other side.
        /// </summary>
        /// <param name="item">Item to send</param>
        /// <param name="token"></param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public virtual Task SendAsync(T item, CancellationToken token = default(CancellationToken))
        {
            CheckInitialized();
            return this._pipe.SendAsync(item, token);
        }

        /// <summary>
        /// Sets the pipe.
        /// </summary>
        /// <param name="pipe">The pipe.</param>
        public virtual void SetPipe(IPipe<T> pipe)
        {
            this._pipe = pipe;
            //this._pipe.StatusChanged += Pipe_ItemDisposed;
        }

        /// <summary>
        /// Called when [reset].
        /// </summary>
        protected override void OnReset()
        {
            this._pipe = null;
            base.OnReset();
        }

        /// <summary>
        /// Checks if the pipe instance is set.
        /// </summary>
        /// <exception cref="PipeNotInitializedException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected void CheckInitialized()
        {
            if (this._pipe == null)
                throw new PipeNotInitializedException();
        }

        #endregion
    }
}
